<?php

require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'LzPod.php';


/**
 *  Variables container.
 *
 *  @author     GoniX aka Giedrius Dubinskas
 *  @created    ?
 *  @changed    2008-01-03  Not total rewrite but every method touched.
 */
class LzVars
        extends LzPod
        implements IteratorAggregate, Countable
{
    public
    function __construct($vars = array())
    {
        if ($vars instanceof self)
            $vars   = $vars->clean()->data;
        else if (!is_array($vars))
            $vars   = Lz::def($vars, array());

        parent::__construct($vars);

        foreach ($this->data as $name => &$var)
            if (is_array($var))
                $var    = $this->prototype()->add($var);
    }


    public
    function __get($name)
    {
        // should we track these to optimize clean() a bit?
        if (!isset($this->data[$name]))
            $this->data[$name]  = $this->prototype();
//Lz::dbg($name, $this->data);

        return $this->data[$name];
    }


    public
    function __set($name, $value)
    {
        if (is_array($value))
            $this->data[$name]  = $this->prototype()->add($value);
        else
            $this->data[$name]  = $value;
//Lz::dbg($name, $this->data);
    }


    public
    function __isset($name)
    {
        return isset($this->clean()->data[$name]);
    }


    public
    function __unset($name)
    {
        if (isset($this->data[$name]))
            unset($this->data[$name]);
    }


    public
    function __toString()
    {
        return $this->toStr();
    }


    public
    function toStr($delimeter = ' ')
    {
        $strings    = array();
        foreach ($this->clean()->data as &$val)
        {
            if ($val instanceof self)
                $strings[]  = $val->toStr($delimeter);
            else
                $strings[]  = (string)$val;
        }
        return join($delimeter, $strings);
    }


    public
    function toArr()
    {
        $arr    = array();
        foreach ($this->clean()->data as $name => $val)
        {
            if ($val instanceof self)
                $arr[$name] = $val->toArr();
            else
                $arr[$name] = $val;
        }
        return $arr;
    }


    public
    function add($vars)
    {
        $args   = func_get_args();
        foreach ($args as $vars)
        {
            if (!Lz::eachable($vars))
                $vars   = array($vars);
            foreach ($vars as $name => $val)
            {
                if (is_array($val))
                    $val    = $this->prototype()->add($val);

                if (self::isNumeric($name))
                    $this->data[]       = $val;
                else
                    $this->data[$name]  = $val;
            }
        }

        return $this;
    }


    public
    function merge($vars)
    {
        $args   = func_get_args();
        foreach ($args as &$vars)
        {
            if (!Lz::eachable($vars))
                $vars   = array($vars);

            foreach ($vars as $name => &$val)
            {
                if (is_array($val))
                    $val    = $this->prototype()->add($val);

                if (self::isNumeric($name))
                    $this->data[]       = $val;
                else if ($val instanceof self && isset($this->data[$name])
                        && $this->data[$name] instanceof self)
                    $this->data[$name]->merge($val);
                else
                    $this->data[$name]  = $val;
            }
        }

        return $this;
    }


    public
    function isEmpty()
    {
        return empty($this->clean()->data);
    }


    public
    function count()
    {
        return count($this->clean()->data);
    }


    public
    function clear()
    {
        $this->data = array();
    }


    public
    function getIterator()
    {
        return new ArrayIterator($this->clean()->data);
    }


    protected
    function attach(&$data)
    {
        if (is_null($data))
            $data   = array();

        return parent::attach($data);
    }


    protected
    function clean()
    {
        foreach ($this->data as $name => &$val)
            if ($val instanceof self && empty($val->clean()->data))
                unset($this->data[$name]);

        return $this;
    }


    static protected
    function isNumeric($name)
    {
        return preg_match('/^-?\d+$/', $name);
    }

}

